Skip to content

Method: {...}

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: *
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: *
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.model;
16:
17: import cz.cvut.kbss.jopa.exceptions.OWLEntityExistsException;
18: import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException;
19: import cz.cvut.kbss.jopa.exceptions.TransactionRequiredException;
20: import cz.cvut.kbss.jopa.model.annotations.CascadeType;
21: import cz.cvut.kbss.jopa.model.descriptors.Descriptor;
22: import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor;
23: import cz.cvut.kbss.jopa.model.metamodel.Attribute;
24: import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
25: import cz.cvut.kbss.jopa.model.query.Query;
26: import cz.cvut.kbss.jopa.model.query.TypedQuery;
27: import cz.cvut.kbss.jopa.sessions.ServerSession;
28: import cz.cvut.kbss.jopa.sessions.UnitOfWorkImpl;
29: import cz.cvut.kbss.jopa.transactions.EntityTransaction;
30: import cz.cvut.kbss.jopa.transactions.EntityTransactionWrapper;
31: import cz.cvut.kbss.jopa.transactions.TransactionWrapper;
32: import cz.cvut.kbss.jopa.utils.*;
33: import org.slf4j.Logger;
34: import org.slf4j.LoggerFactory;
35:
36: import java.net.URI;
37: import java.util.Collection;
38: import java.util.List;
39: import java.util.Objects;
40:
41: public class EntityManagerImpl extends AbstractEntityManager implements Wrapper {
42:
43: private static final Logger LOG = LoggerFactory.getLogger(EntityManagerImpl.class);
44:
45: private EntityManagerFactoryImpl emf;
46:
47: private boolean open;
48:
49: private TransactionWrapper transaction;
50: private UnitOfWorkImpl persistenceContext;
51: private ServerSession serverSession;
52: private final Configuration configuration;
53:
54: public EntityManagerImpl(EntityManagerFactoryImpl emf, Configuration configuration,
55: ServerSession serverSession) {
56: this.emf = emf;
57: this.serverSession = serverSession;
58: this.configuration = configuration;
59:
60: this.setTransactionWrapper();
61:
62: this.open = true;
63: }
64:
65: public enum State {
66: MANAGED, MANAGED_NEW, NOT_MANAGED, REMOVED
67: }
68:
69: @Override
70: public void persist(final Object entity) {
71: final Descriptor d = new EntityDescriptor();
72: persist(entity, d);
73: }
74:
75: @Override
76: public void persist(final Object entity, final Descriptor descriptor) {
77: LOG.trace("Persisting {}", entity);
78: ensureOpen();
79: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
80: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
81:
82: switch (getState(entity, descriptor)) {
83: case NOT_MANAGED:
84: try {
85: getCurrentPersistenceContext().registerNewObject(entity, descriptor);
86: } catch (RuntimeException e) {
87: if (getTransaction().isActive()) {
88: getTransaction().setRollbackOnly();
89: }
90: throw e;
91: }
92: case MANAGED:
93: new OneLevelCascadeExplorer() {
94: @Override
95: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
96: try {
97: Object ox = EntityPropertiesUtils.getAttributeValue(at, o);
98: LOG.trace("object={}, attribute={}, value={}", o, at.getName(), ox);
99: if (ox == null) {
100: return;
101: }
102: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
103: if (at.isCollection()) {
104: for (final Object ox2 : (Collection<?>) ox) {
105: persist(ox2, attDescriptor);
106: }
107: } else {
108: persist(ox, attDescriptor);
109: }
110: } catch (Exception e) {
111: if (getTransaction().isActive()) {
112: getTransaction().setRollbackOnly();
113: }
114: throw new OWLPersistenceException(
115: "A problem occured when persisting attribute " + at.getName()
116: + " of with value " + o + " of object " + entity, e);
117: }
118: }
119: }.start(this, entity, CascadeType.PERSIST);
120: break;
121: case MANAGED_NEW:
122: throw new OWLEntityExistsException("Entity " + entity
123: + " is already managed in this persistence context.");
124: case REMOVED:
125: getCurrentPersistenceContext().revertObject(entity);
126: break;
127: }
128: }
129:
130: @Override
131: public <T> T merge(final T entity) {
132: final Descriptor d = new EntityDescriptor();
133: return merge(entity, d);
134: }
135:
136: @Override
137: public <T> T merge(final T entity, final Descriptor descriptor) {
138: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
139: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
140:
141: return mergeInternal(entity, descriptor);
142: }
143:
144: /**
145: * Merges state of the specified entity into the current persistence context. </p>
146: *
147: * @param entity Entity instance
148: * @param descriptor Contains information about contexts into which the entity and its field should be merged
149: * @return Managed instance of the merged entity
150: */
151: private <T> T mergeInternal(final T entity, final Descriptor descriptor) {
152: assert entity != null;
153: assert descriptor != null;
154: LOG.trace("Merging {}", entity);
155: ensureOpen();
156:
157: Class<T> clz = (Class<T>) entity.getClass();
158:
159: switch (getState(entity, descriptor)) {
160: case MANAGED_NEW:
161: case MANAGED:
162: new OneLevelCascadeExplorer() {
163: @Override
164: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
165: mergeX(at, o, descriptor);
166: }
167: }.start(this, entity, CascadeType.MERGE);
168: return entity;
169: case NOT_MANAGED:
170: final T merged;
171: merged = getCurrentPersistenceContext().mergeDetached(entity, descriptor);
172:
173: new OneLevelCascadeExplorer() {
174: @Override
175: protected void exploreCascaded(Attribute<?, ?> at, Object o) {
176: final Descriptor attDescriptor = descriptor.getAttributeDescriptor(at);
177: mergeX(at, o, attDescriptor);
178: }
179:
180: @Override
181: protected void exploreNonCascaded(Attribute<?, ?> at, Object o) {
182: final Object attVal = EntityPropertiesUtils.getAttributeValue(at, o);
183: EntityPropertiesUtils.setFieldValue(at.getJavaField(), o, attVal);
184: }
185: }.start(this, merged, CascadeType.MERGE);
186: return merged;
187: case REMOVED:
188: default:
189: throw new IllegalArgumentException();
190: }
191: }
192:
193: private void mergeX(Attribute<?, ?> at, Object o, Descriptor descriptor) {
194: Object attVal = EntityPropertiesUtils.getAttributeValue(at, o);
195: if (attVal == null) {
196: return;
197: }
198: if (at.isCollection()) {
199: Collection c = (Collection) attVal;
200: Collection merged = CollectionFactory.createInstance(c);
201: for (final Object ox2 : c) {
202: merged.add(mergeInternal(ox2, descriptor));
203: }
204: attVal = getCurrentPersistenceContext().createIndirectCollection(merged, o, at.getJavaField());
205: } else {
206: attVal = mergeInternal(attVal, descriptor);
207: }
208: EntityPropertiesUtils.setFieldValue(at.getJavaField(), o, attVal);
209: }
210:
211: @Override
212: public void remove(Object object) {
213: ensureOpen();
214:
215: switch (getState(object)) {
216: case MANAGED_NEW:
217: case MANAGED:
218: getCurrentPersistenceContext().removeObject(object);
219: // Intentional fall-through
220: case REMOVED:
221: new SimpleOneLevelCascadeExplorer() {
222: @Override
223: protected void runCascadedForEach(Object ox2) {
224: remove(ox2);
225: }
226: }.start(this, object, CascadeType.REMOVE);
227: break;
228: case NOT_MANAGED:
229: throw new IllegalArgumentException("Entity " + object
230: + " is not managed and cannot be removed.");
231: }
232: }
233:
234: @Override
235: public <T> T find(Class<T> cls, Object primaryKey) {
236: final EntityDescriptor d = new EntityDescriptor();
237: return find(cls, primaryKey, d);
238: }
239:
240: @Override
241: public <T> T find(Class<T> cls, Object primaryKey, Descriptor descriptor) {
242: Objects.requireNonNull(cls, ErrorUtils.constructNPXMessage("cls"));
243: Objects.requireNonNull(primaryKey, ErrorUtils.constructNPXMessage("primaryKey"));
244: Objects.requireNonNull(descriptor, ErrorUtils.constructNPXMessage("descriptor"));
245:
246: ensureOpen();
247: LOG.trace("Finding instance of {} with identifier {} in context ", cls, primaryKey, descriptor);
248: final URI uri = (primaryKey instanceof URI) ? (URI) primaryKey : URI.create(primaryKey.toString());
249:
250: return getCurrentPersistenceContext().readObject(cls, uri, descriptor);
251: }
252:
253: @Override
254: public void flush() {
255: ensureOpen();
256:
257: LOG.trace("Flushing changes...");
258: if (!getTransaction().isActive()) {
259: throw new TransactionRequiredException();
260: }
261: this.getCurrentPersistenceContext().writeUncommittedChanges();
262: }
263:
264: @Override
265: public void refresh(Object entity) {
266: ensureOpen();
267: Objects.requireNonNull(entity, ErrorUtils.constructNPXMessage("entity"));
268:
269: this.getCurrentPersistenceContext().revertObject(entity);
270: new SimpleOneLevelCascadeExplorer() {
271: @Override
272: protected void runCascadedForEach(Object ox2) {
273: refresh(ox2);
274: }
275: }.start(this, entity, CascadeType.REFRESH);
276: }
277:
278: @Override
279: public void clear() {
280: getCurrentPersistenceContext().clear();
281: }
282:
283: @Override
284: public void detach(Object entity) {
285: ensureOpen();
286:
287: switch (getState(entity)) {
288: case MANAGED_NEW:
289: case MANAGED:
290: getCurrentPersistenceContext().unregisterObject(entity);
291: new SimpleOneLevelCascadeExplorer() {
292: @Override
293: protected void runCascadedForEach(Object ox2) {
294: detach(ox2);
295: }
296: }.start(this, entity, CascadeType.DETACH);
297: break;
298: default:
299: break;
300: }
301: }
302:
303: @Override
304: public boolean contains(Object entity) {
305: ensureOpen();
306: return getCurrentPersistenceContext().contains(entity);
307: }
308:
309: @Override
310: public void close() {
311: ensureOpen();
312: removeCurrentPersistenceContext();
313: open = false;
314: }
315:
316: public boolean isOpen() {
317: return open;
318: }
319:
320: @Override
321: public EntityTransaction getTransaction() {
322: return transaction.getTransaction();
323: }
324:
325: @Override
326: public EntityManagerFactoryImpl getEntityManagerFactory() {
327: return emf;
328: }
329:
330: @Override
331: public Metamodel getMetamodel() {
332: return emf.getMetamodel();
333: }
334:
335: @Override
336: public boolean isLoaded(final Object object, final String attributeName) {
337: // TODO
338: return false;
339: }
340:
341: @Override
342: public Query createQuery(String qlString) {
343: return getCurrentPersistenceContext().createQuery(qlString);
344: }
345:
346: @Override
347: public <T> TypedQuery<T> createQuery(String query, Class<T> resultClass) {
348: return getCurrentPersistenceContext().createQuery(query, resultClass);
349: }
350:
351: @Override
352: public Query createNativeQuery(String sqlString) {
353: return getCurrentPersistenceContext().createNativeQuery(sqlString);
354: }
355:
356: @Override
357: public <T> TypedQuery<T> createNativeQuery(String sqlString, Class<T> resultClass) {
358: return getCurrentPersistenceContext().createNativeQuery(sqlString, resultClass);
359: }
360:
361: @Override
362: public boolean isConsistent(URI context) {
363: return getCurrentPersistenceContext().isConsistent(context);
364: }
365:
366: @Override
367: public List<URI> getContexts() {
368: return getCurrentPersistenceContext().getContexts();
369: }
370:
371: @Override
372: public void setUseTransactionalOntologyForQueryProcessing() {
373: getCurrentPersistenceContext().setUseTransactionalOntologyForQueryProcessing();
374: }
375:
376: @Override
377: public boolean useTransactionalOntologyForQueryProcessing() {
378: return getCurrentPersistenceContext().useTransactionalOntologyForQueryProcessing();
379: }
380:
381: @Override
382: public void setUseBackupOntologyForQueryProcessing() {
383: getCurrentPersistenceContext().setUseBackupOntologyForQueryProcessing();
384: }
385:
386: @Override
387: public boolean useBackupOntologyForQueryProcessing() {
388: return getCurrentPersistenceContext().useBackupOntologyForQueryProcessing();
389: }
390:
391: @Override
392: public <T> T unwrap(Class<T> cls) {
393: if (cls.isAssignableFrom(this.getClass())) {
394: return cls.cast(this);
395: }
396: return getCurrentPersistenceContext().unwrap(cls);
397: }
398:
399: @Override
400: public Object getDelegate() {
401: return unwrap(EntityManagerImpl.class);
402: }
403:
404: private void ensureOpen() {
405: if (!isOpen()) {
406: throw new OWLPersistenceException("The entity manager is closed !");
407: }
408: }
409:
410: private State getState(Object entity) {
411: return getCurrentPersistenceContext().getState(entity);
412: }
413:
414: private State getState(Object entity, Descriptor descriptor) {
415: return getCurrentPersistenceContext().getState(entity, descriptor);
416: }
417:
418: @Override
419: protected void finalize() throws Throwable {
420: if (isOpen()) {
421: close();
422: }
423: super.finalize();
424: }
425:
426: @Override
427: public UnitOfWorkImpl getCurrentPersistenceContext() {
428: if (this.persistenceContext == null) {
429: this.persistenceContext = (UnitOfWorkImpl) this.serverSession.acquireUnitOfWork();
430: persistenceContext.setEntityManager(this);
431: }
432: return this.persistenceContext;
433: }
434:
435: /**
436: * Called from EntityTransaction in case of a rollback. Releasing the UoW is up to the EntityTransaction.
437: */
438: @Override
439: public void removeCurrentPersistenceContext() {
440: if (persistenceContext != null && persistenceContext.isActive()) {
441: persistenceContext.release();
442: }
443: this.persistenceContext = null;
444: }
445:
446: @Override
447: public void transactionStarted(EntityTransaction t) {
448: this.serverSession.transactionStarted(t, this);
449: }
450:
451: @Override
452: public void transactionFinished(EntityTransaction t) {
453: this.serverSession.transactionFinished(t);
454: }
455:
456: /**
457: * Since we support only EntityTransactions, we set the TransactionWrapper to EntityTransactionWrapper. In the
458: * future, if JTA transactions are supported, JTATransactionWrapper should be set instead of the
459: * EntityTransactionWrapper.
460: */
461: private void setTransactionWrapper() {
462: this.transaction = new EntityTransactionWrapper(this);
463: }
464:
465: @Override
466: public Configuration getConfiguration() {
467: return configuration;
468: }
469: }